﻿
Imports osi.root.connector
Imports osi.root.event
Imports osi.root.formation
Imports osi.root.lock
Imports osi.root.procedure
Imports osi.root.template
Imports osi.root.utils

Public Class async_lazier(Of T, THREAD_SAFE As _boolean)
    Private Shared ReadOnly threadsafe As Boolean

    Shared Sub New()
        threadsafe = +alloc(Of THREAD_SAFE)()
    End Sub

    Private ReadOnly ts As async_thread_safe_lazier(Of T)
    Private ReadOnly tus As async_thread_unsafe_lazier(Of T)

    Public Sub New(ByVal d As Func(Of pointer(Of T), event_comb))
        If threadsafe Then
            ts = New async_thread_safe_lazier(Of T)(d)
        Else
            tus = New async_thread_unsafe_lazier(Of T)(d)
        End If
    End Sub

    Public Sub New(ByVal v As T)
        If threadsafe Then
            ts = New async_thread_safe_lazier(Of T)(v)
        Else
            tus = New async_thread_unsafe_lazier(Of T)(v)
        End If
    End Sub

    Public Function alive() As Boolean
        If threadsafe Then
            assert(Not ts Is Nothing)
            Return ts.alive()
        Else
            assert(Not tus Is Nothing)
            Return tus.alive()
        End If
    End Function

    Public Function [get](ByRef r As T) As Boolean
        If threadsafe Then
            assert(Not ts Is Nothing)
            Return ts.get(r)
        Else
            assert(Not tus Is Nothing)
            Return tus.get(r)
        End If
    End Function

    Public Function [get](ByVal r As pointer(Of T)) As event_comb
        Dim ec As event_comb = Nothing
        Return New event_comb(Function() As Boolean
                                  If threadsafe Then
                                      assert(Not ts Is Nothing)
                                      ec = ts.get(r)
                                  Else
                                      assert(Not tus Is Nothing)
                                      ec = tus.get(r)
                                  End If
                                  assert(Not ec Is Nothing)
                                  Return waitfor(ec) AndAlso
                                         goto_next()
                              End Function,
                              Function() As Boolean
                                  Return ec.end_result() AndAlso
                                         goto_end()
                              End Function)
    End Function
End Class

Public Class async_thread_unsafe_lazier(Of T)
    Private ReadOnly d As Func(Of pointer(Of T), event_comb)
    Private initialized As Boolean
    Private v As T

    Private Sub New(ByVal initialized As Boolean)
        Me.initialized = initialized
        Me.d = Nothing
        Me.v = Nothing
    End Sub

    Public Sub New()
        Me.New(False)
    End Sub

    Public Sub New(ByVal d As Func(Of pointer(Of T), event_comb))
        Me.New(False)
        assert(Not d Is Nothing)
        Me.d = d
    End Sub

    Public Sub New(ByVal v As T)
        Me.New(True)
        assert(Not v Is Nothing)
        Me.v = v
    End Sub

    Public Function alive() As Boolean
        Return initialized
    End Function

    Public Function [get](ByRef r As T) As Boolean
        If alive() Then
            r = v
            Return True
        Else
            assert_begin([get](DirectCast(Nothing, pointer(Of T))))
            Return False
        End If
    End Function

    Protected Overridable Function initialize(ByVal r As pointer(Of T)) As event_comb
        assert(Not d Is Nothing)
        Return d(r)
    End Function

    Public Function [get](ByVal r As pointer(Of T)) As event_comb
        Dim ec As event_comb = Nothing
        Return New event_comb(Function() As Boolean
                                  If Not initialized Then
                                      assert(v Is Nothing OrElse is_valuetype(Of T)())
                                      r.renew()
                                      ec = initialize(r)
                                      Return waitfor(ec) AndAlso
                                             goto_next()
                                  Else
                                      Return eva(r, v) AndAlso
                                             goto_end()
                                  End If
                              End Function,
                              Function() As Boolean
                                  If ec.end_result() Then
                                      v = (+r)
                                  End If
                                  initialized = True
                                  Return goto_end()
                              End Function)
    End Function
End Class

Public Class async_thread_safe_lazier(Of T)
    Private ReadOnly finish_get As signal_event
    Private ReadOnly d As Func(Of pointer(Of T), event_comb)
    Private initialized As Boolean
    Private begin_get As singleentry
    Private v As T

    Private Sub New(ByVal initialized As Boolean)
        Me.initialized = initialized
        Me.d = Nothing
        Me.v = Nothing
        If initialized Then
            Me.finish_get = Nothing
        Else
            Me.finish_get = New signal_event()
        End If
    End Sub

    Public Sub New()
        Me.New(False)
    End Sub

    Public Sub New(ByVal d As Func(Of pointer(Of T), event_comb))
        Me.New(False)
        assert(Not d Is Nothing)
        Me.d = d
    End Sub

    Public Sub New(ByVal v As T)
        Me.New(True)
        assert(Not v Is Nothing)
        Me.v = v
    End Sub

    Public Function alive() As Boolean
        Return initialized
    End Function

    Public Function [get](ByRef r As T) As Boolean
        If alive() Then
            r = v
            Return True
        Else
            assert_begin([get](DirectCast(Nothing, pointer(Of T))))
            Return False
        End If
    End Function

    Protected Overridable Function prepare(ByVal r As pointer(Of T)) As event_comb
        assert(Not d Is Nothing)
        Return d(r)
    End Function

    Public Function [get](ByVal r As pointer(Of T)) As event_comb
        Dim ec As event_comb = Nothing
        Return New event_comb(Function() As Boolean
                                  If Not initialized Then
                                      If begin_get.mark_in_use() Then
                                          assert(v Is Nothing OrElse is_valuetype(Of T)())
                                          r.renew()
                                          ec = d(r)
                                          Return waitfor(ec) AndAlso
                                                 goto_next()
                                      Else
                                          Return waitfor(finish_get) AndAlso
                                                 goto_next()
                                      End If
                                  Else
                                      Return eva(r, v) AndAlso
                                             goto_end()
                                  End If
                              End Function,
                              Function() As Boolean
                                  If ec Is Nothing Then
                                      assert(initialized)
                                      Return eva(r, v) AndAlso
                                             goto_end()
                                  Else
                                      If ec.end_result() Then
                                          v = (+r)
                                      End If
                                      initialized = True
                                      finish_get.mark()
                                      Return goto_end()
                                  End If
                              End Function)
    End Function
End Class
